package com.jxm.jdk8features;

import org.junit.Test;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @Description: lambda表达式方法引用
 * @Author: JXM
 * @Date: 2023-12-25 21:51
 */
public class MethodReference {

    /**
     * 静态方法引用：
     * 描述：如果我们在重写方法的时候，方法体中只有一行代码，并且这行代码是调用了某个类的静态方法，
     *   并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中，这个时候我们就可以引用类的静态方法。
     * 类名::静态方法
     * 使用场景：
     *   如果某个lambda表达式里只是调用一个静态方法，并且前后参数的形式一致，就可以使用静态方法引用
     */
    @Test
    public void test1(){
        Student[] students = new Student[4];
        students[0] = new Student("zhangsan",154.55,20);
        students[1] = new Student("lisi",185.14,36);
        students[2] = new Student("wangwu",160.55,18);
        students[3] = new Student("zhaoliu",178.42,40);

        //原始写法：对数组中的学生对象，按照年龄升序排序
//        Arrays.sort(students, new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return o1.getAge() - o2.getAge();
//            }
//        });
        //简化1
//        Arrays.sort(students,((o1, o2) -> o1.getAge() - o2.getAge()));
//        Arrays.sort(students,((o1, o2) ->CompareByData.CompareByAge(o1,o2)));

        //简化2 静态方法引用
        Arrays.sort(students,CompareByData::CompareByAge);

        System.out.println(Arrays.toString(students));
    }

    /**
     * 实例方法引用：
     * 描述：如果我们在重写方法的时候，方法体中只有一行代码，并且这行代码是调用了某个对象的成员方法，
     * 并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中，这个时候我们就可以引用对象的实例方法
     *   对象名::实例方法
     * 使用场景：
     *   如果某个lambda表达式里只是调用一个实例方法，并且前后参数的形式一致，就可以使用实例方法引用
     */
    @Test
    public void test1_1(){
        Student[] students = new Student[4];
        students[0] = new Student("zhangsan",154.55,20);
        students[1] = new Student("lisi",185.14,36);
        students[2] = new Student("wangwu",160.55,18);
        students[3] = new Student("zhaoliu",178.42,40);

        CompareByData compare = new CompareByData();

        //匿名内部类方式
//        Arrays.sort(students, new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return compare.CompareByAgeDesc(o1,o2);
//            }
//        });
        //简化1
//        Arrays.sort(students,((o1, o2) -> o2.getAge() - o1.getAge())); //降序

//        Arrays.sort(students,((o1, o2) -> compare.CompareByAgeDesc(o1,o2)));

        //简化2 实例方法引用
        Arrays.sort(students,compare::CompareByAgeDesc);
        System.out.println(Arrays.toString(students));
    }

    /**
     * 特定类型(引用类型的实例方法)方法引用：
     * 描述：如果我们在重写方法的时候，方法体中只有一行代码，并且这行代码是调用了第一个参数的成员方法，
     * 并且我们把要重写的抽象方法中剩余的所有的参数都按照顺序传入了这个成员方法中，这个时候我们就可以引用类的实例方法。
     *   类型::静态方法
     * 使用场景：
     *   如果某个Lambda表达式里只是调用一个实例方法，并且前面参数列表中的第一个参数是作为方法的主调，
     *   后面的所有参数都是作为该实例方法的入参的，则此时就可以使用特定类型的方法引用。
     */
    class A implements Comparator<String>{
        @Override
        public int compare(String o1, String o2) {
            return o1.compareToIgnoreCase(o2);
        }
    }
    @Test
    public void test2(){
        A a = new A();

        String[] names = {"boby", "angela", "Andy" ,"dlei", "caocao", "Babo", "jack", "Cici"};
        //排序
//        Arrays.sort(names);
//        Arrays.sort(names,a);
        //忽略大小写排序
//        Arrays.sort(names, new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                return o1.compareToIgnoreCase(o2);
//            }
//        });
        //简化1
//        Arrays.sort(names, (o1, o2) -> o1.compareToIgnoreCase(o2));

        //简化2 特定类型方法引用
        Arrays.sort(names, String::compareToIgnoreCase);

        System.out.println(Arrays.toString(names));

        /**
         * 这种也是属于类的实例方法引用
         *
         * List<Author> authors = getAuthors();
         * authors.stream()
         *  .map(Author::getName)
         *  .forEach(str -> System.out.println(str));
         */
    }

    /**
     * 构造器引用：
     * 描述：如果我们在重写方法的时候，方法体中只有一行代码，并且这行代码是调用了某个类的构造方法，
     * 并且我们把要重写的抽象方法中的所有的参数都按照顺序传入了这个构造方法中，这个时候我们就可以引用构造器。
     *  类名::new
     * 使用场景：
     *  如果某个lambda表达式里只是创建对象，并且前后参数情况一致，就可以使用构造器引用
     */
    @Test
    public void test3(){
        //创建这个接口的匿名内部内对象
        CreateCar cc1 = new CreateCar() {
            @Override
            public Car create(String name, double price) {
                return new Car(name,price);
            }
        };
        //简化1
//        CreateCar cc2 = ( name,  price) -> new Car(name,price);

        //简化2 构造器引用
        CreateCar cc = Car::new;

        Car c = cc1.create("奔驰", 199.88);
        System.out.println(c);
    }

}
